/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package org.dusin.teachassist.poi;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.NotDirectoryException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hwpf.extractor.WordExtractor;
import org.apache.poi.ooxml.POIXMLDocument;
import org.apache.poi.ooxml.extractor.POIXMLTextExtractor;
import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
import org.apache.poi.openxml4j.opc.OPCPackage;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.xwpf.extractor.XWPFWordExtractor;

import org.apache.xmlbeans.XmlException;
import org.dusin.teachassist.matchalg.BasicData;
import org.dusin.teachassist.matchalg.DegreeData;
import org.dusin.teachassist.matchalg.MatchStrategy;
import org.dusin.teachassist.matchalg.MaxSubString;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;

/**
 * POI 4.0
 * @author dusin
 */
public class WordPOITest1 {

    public WordPOITest1() {
    }

    @BeforeClass
    public static void setUpClass() {
    }

    @AfterClass
    public static void tearDownClass() {
    }

    @Before
    public void setUp() {
    }

    @After
    public void tearDown() {
    }

    
   

    String matchExcelFileDir = "C:\\Users\\vcc\\OneDrive\\2019-2020第一学期\\计算机程序设计语言Java\\实验报告\\1";

    // @Test
    // public void hello() {}
   

    Map<String, String> errorFileMap = new HashMap<String, String>();

    private List<Path> getAllValidFiles(String directory) throws IOException {
        List<Path> filesList = new ArrayList<Path>();
        Path path = Paths.get(directory);
        DirectoryStream<Path> directoryStream = Files.newDirectoryStream(path);
        for (Path p : directoryStream) {
            if (isValidFile(p)) {
                filesList.add(p);
            } else {
                System.out.println(p.toFile().getName()+ ":文件名格式不正确");
                errorFileMap.put(p.toFile().getName(), "文件名格式不正确");
            }
        }
        return filesList;
    }

    @Test
    public void testGetAllValidFiles() {
        try {
            getAllValidFiles("c:\\abc");
        } catch (NotDirectoryException ex) {
            Logger.getLogger(WordPOITest1.class.getName()).log(Level.SEVERE, null, ex);
        } catch (NoSuchFileException e) {
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

  
    //所有文件的匹配列表
    List<Map<String,Object>> allList = new ArrayList<Map<String,Object>>();
    String splitPattern = "[\\t\\n\\r{}]";

    private void getAllList(List<Path> allFiles) {
        for (Path p : allFiles) {
            Map<String,Object> docInfoMap = new HashMap<String,Object>();
            String filename = p.toFile().getName();
            docInfoMap.put("filename", filename);
            docInfoMap.put("maxDegree", new Double(0));//与其他文档的最高重复率
      
            String text = getText(p);
            String[] statements = text.split(splitPattern);
            List<String> statementList = cleanData(statements);
        
            docInfoMap.put("statements", statementList);
            allList.add(docInfoMap);
        }
    }

    //计算匹配度
    public void calculatorAllDegree() {
        for (Map<String,Object> docInfoI : allList) {
            List<Map<String,Object>> degreeList = new ArrayList<Map<String,Object>>();
            for (Map<String,Object> docInfoJ : allList) {
                if (docInfoI != docInfoJ) {
                    double degree = getDegree((List<String>)docInfoI.get("statements"), 
                            (List<String>)docInfoJ.get("statements"));

                    if (degree > 0.8) {   //匹配度超阈值，加入
                        Map<String,Object> docDegree = new HashMap<String,Object>();
                        docDegree.put("filename", docInfoJ.get("filename"));
                        docDegree.put("degree", degree);
                        degreeList.add(docDegree);
                    }
                }
            }
            docInfoI.put("degreeList",degreeList);
        }
    }

    //输出Excel文件
    public void createExcel() {
        OutputStream fileOut = null;
        try {
            Workbook wb = new HSSFWorkbook();
            Sheet sheet = wb.createSheet("sheet");
            // Create a row and put some cells in it. Rows are 0 based.
            Row row = sheet.createRow(0);
            // Create a cell and put a value in it.
            Cell cell = row.createCell(0);
            cell.setCellValue("文件名");            
            cell = row.createCell(1);
            cell.setCellValue("匹配度");
            int r = 1;
            for (Map<String,Object> docInfo : allList) {
                row = sheet.createRow(r);
                // Create a cell and put a value in it.
                cell = row.createCell(0);
                cell.setCellValue((String)docInfo.get("filename"));              
                cell = row.createCell(1);
                StringBuilder degrees = new StringBuilder();
                for (Map<String,Object> d : (List<Map<String,Object>>)docInfo.get("degreeList")){
                    degrees.append("(").append(d.get("filename")).append(",")
                            .append(d.get("degree")).append(")");                    
                }
                cell.setCellValue(degrees.toString());
                r++;
            }
            String filename = matchExcelFileDir +  "匹配度.xls";
            fileOut = new FileOutputStream(filename);
            wb.write(fileOut);
            wb.close();
            System.out.println(filename + " 生成成功");

        } catch (FileNotFoundException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        } finally {
            try {
                fileOut.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }

  

    MatchStrategy ms = new MaxSubString();

    private double getDegree(List<String> a, List<String> b) {
        double matchedLength = 0;
        int totalLength = 0;
        for (int i = 0; i < a.size(); i++) {
            totalLength += a.get(i).length();
            int beginIndex = i - 8 < 0 ? 0 : i - 8;
            int endIndex = i + 8 > b.size() ? b.size() : i + 8;
            int max = 0;
            for (int j = beginIndex; j < endIndex; j++) {
                int degree = ms.getMatchLength(a.get(i), b.get(j));
                if (max < degree) {
                    max = degree;
                }
                if ((double) max / a.get(i).length() > 0.99) {
                    break;
                }
            }
            matchedLength += max;
        }
        return (double) matchedLength / totalLength;
    }

    
    
    @Test
    public void testREFilenmame() {
        String filename = "162210501104史倩作业1.docx";
        File file = new File(filename);
        System.out.println(file.getName());

        //filename="8989898989史倩";
        String pattern = "^[\\d]{8,15}[\u4e00-\u9fa5]{1,6}(作业|实验|实验报告)\\d{1}.(docx|doc)$";
        boolean flag = filename.matches(pattern);
        Assert.assertTrue("", flag);
        System.out.println(flag);
    }

    private boolean isValidFile(Path p) {
        String filename = p.toFile().getName();
        //String pattern = "^[\\d]{8,15}[\u4e00-\u9fa5]{1,6}(作业|实验|实验报告)\\d{1}.(docx|doc)$";
        String pattern = ".*.(docx|doc)$";
        return filename.matches(pattern);
    }

    private List<String> cleanData(String[] a) {
        List<String> items = new ArrayList<String>();
        for (String sa : a) {
            if (sa.trim().length() < 5) {
                continue;
            }
            items.add(sa.trim());
        }
        return items;
    }

    private String getText(Path pi) {
        String text = null;
        OPCPackage opcPackage = null;
        POIXMLTextExtractor extractor = null;
        InputStream is = null;
        WordExtractor ex = null;
        String filename = pi.toFile().getName();
        try {
            System.out.println("获取文字：" + filename);
            if (filename.endsWith("doc")) {
                try {
                    is = new FileInputStream(pi.toFile());
                    ex = new WordExtractor(is);
                    text = ex.getText();
                } catch (IllegalArgumentException e) { //如果不是doc格式，尝试用docx格式解析下
                    opcPackage = POIXMLDocument.openPackage(pi.toString());
                    extractor = new XWPFWordExtractor(opcPackage);
                    text = extractor.getText();
                    if (extractor != null) {
                        extractor.close();
                    }
                }                
            } else if (filename.endsWith("docx")) {
                opcPackage = POIXMLDocument.openPackage(pi.toString());
                extractor = new XWPFWordExtractor(opcPackage);
                text = extractor.getText();
                if (extractor != null) {
                    extractor.close();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
            this.errorFileMap.put(filename, e.getMessage());
        } catch (XmlException e) {
            e.printStackTrace();
            this.errorFileMap.put(filename, e.getMessage());
        } catch (OpenXML4JException e) {
            e.printStackTrace();
            this.errorFileMap.put(filename, e.getMessage());
        } finally {
            if (ex != null) {
                try {
                    ex.close();
                } catch (IOException ex1) {
                    ex1.printStackTrace();
                }
            }
            if (is != null) {
                try {
                    is.close();
                } catch (IOException ex1) {
                    ex1.printStackTrace();
                }
            }
            if (extractor != null) {
                try {
                    extractor.close();
                } catch (IOException ex1) {
                    ex1.printStackTrace();
                }
            }
        }
        return text;
    }
    


    //比较某个目录中所有文档的匹配度
    @Test
    public void testDegreeInDirectory() {
        try {
            String dir = "C:\\Users\\vcc\\OneDrive\\2019-2020第一学期\\计算机程序设计语言Java\\实验报告\\1";
            List<Path> files = getAllValidFiles(dir);
            getAllList(files);
            calculatorAllDegree();
            createExcel();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}
